package com.hboxs.asl.wechat.utils;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.io.SAXReader;
import org.json.JSONObject;
import org.json.JSONTokener;

import javax.net.ssl.SSLContext;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * Created by study on 6/26/2015 11:30.
 */
public final class HttpClientUtils {
    private static Logger logger = Logger.getLogger("HttpClientUtils");

    private HttpClientUtils() {

    }

    /**
     * post xml
     * @param url
     * @param xml
     * @return
     */
    public static String postXml(String url, String xml) {
        logger.debug("POST-URL:" + url + ", XML:" + xml);
        HttpClient client = HttpClientBuilder.create().build();
        client = WebClientDevWrapper.wrapClient(client);
        HttpPost post = new HttpPost(url);
        String response = null;
        try {
            StringEntity s = new StringEntity(xml, "UTF-8");
            s.setContentEncoding("UTF-8");
            s.setContentType("application/xml");
            post.setEntity(s);
//            Long startTime = System.currentTimeMillis();
            HttpResponse res = null;
            if (client != null) {
                res = client.execute(post);
            }
//            System.out.println(System.currentTimeMillis() - startTime);
            if (res != null && res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = res.getEntity();
                String charset = "utf-8";
                SAXReader reader = new SAXReader();
                Document document = reader.read(new InputStreamReader(entity.getContent(), charset));
                response = document.asXML();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return response;
    }

    /**
     * post json
     * @param url
     * @param json
     * @return
     */
    public static JSONObject post(String url, String json) {
        json = json.replaceAll(" " , "");
        HttpClient client = HttpClientBuilder.create().build();
        client = WebClientDevWrapper.wrapClient(client);
        HttpPost post = new HttpPost(url);
        JSONObject response = null;
        try {
            StringEntity s = new StringEntity(json, "UTF-8");
            s.setContentEncoding("UTF-8");
            s.setContentType("application/json");
            post.setEntity(s);
            HttpResponse res = null;
            if (client != null) {
                res = client.execute(post);
            }
            if (res != null && res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = res.getEntity();
                String charset = "utf-8";
                response = new JSONObject(new JSONTokener(new InputStreamReader(entity.getContent(), charset)));
                if (response.has("errcode") && response.getInt("errcode") > 0) {
                    logger.error(response.toString());
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return response;
    }

    /**
     * get json
     * @param url
     * @return
     */
    public static JSONObject get(String url) {
        HttpClient client = HttpClientBuilder.create().build();
        client = WebClientDevWrapper.wrapClient(client);
        HttpGet get = new HttpGet(url);
        JSONObject response = null;
        try {
            HttpResponse res = null;
            if (client != null) {
                res = client.execute(get);
            }
            if (res != null && res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = res.getEntity();
                String charset = "utf-8";
                response = new JSONObject(new JSONTokener(
                        new InputStreamReader(entity.getContent(), charset)));
                if (response.has("errcode") && response.getInt("errcode") > 0) {
                    logger.error(response.toString());
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return response;
    }

    private static class WebClientDevWrapper {
        public static HttpClient wrapClient(HttpClient base) {
            try {
                RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.create();
                ConnectionSocketFactory plainSF = new PlainConnectionSocketFactory();
                registryBuilder.register("http", plainSF);
                //指定信任密钥存储对象和连接套接字工厂
                try {
                    KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
                    SSLContext sslContext = SSLContexts.custom().useTLS().loadTrustMaterial(trustStore, new AnyTrustStrategy()).build();
                    LayeredConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                    registryBuilder.register("https", sslSF);
                } catch (KeyStoreException e) {
                    throw new RuntimeException(e);
                } catch (KeyManagementException e) {
                    throw new RuntimeException(e);
                } catch (NoSuchAlgorithmException e) {
                    throw new RuntimeException(e);
                }
                Registry<ConnectionSocketFactory> registry = registryBuilder.build();
                //设置连接管理器
                PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry);
                connManager.setDefaultConnectionConfig(ConnectionConfig.custom().setCharset(Charset.forName("UTF-8")).build());
                connManager.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(100000).build());
                //构建客户端
                return HttpClientBuilder.create().setConnectionManager(connManager).build();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        private static class AnyTrustStrategy implements TrustStrategy {
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        }
    }

}
